Section 3.5.1.6
Julia Fractal


A julia fractal.

A julia fractal object is a 3-D slice of a 4-D object created by generalizing the process used to create the classic Julia sets. You can make a wide variety of strange objects using julia_fractal, including some that look like bizarre blobs of twisted taffy.

The julia_fractal syntax (with default values listed in comments) is:

julia_fractal { 4DJULIA_PARAMETER // default is <1,0,0,0> [ quaternion | hypercomplex ] // default is quaternion [ sqr | cube | exp | reciprocal | sin | asin | sinh | asinh | cos | acos | cosh | acosh | tan | atan | tanh | atanh | log | pwr(X,Y) ] // default is sqr [ max_iteration MAX_ITERATION ] // default value 20 [ precision PRECISION ] // default value 20 [ slice 4DNORMAL, DISTANCE ] // default <0,0,0,1>,0 }

The 4-D vector 4DJULIA_PARAMETER is the classic Julia parameter p in the iterated formula f(h) + p.

The julia_fractal object is calculated by using an algorithm that determines whether an arbitrary point h(0) in 4-D space is inside or outside the object. The algorithm requires generating the sequence of vectors h(0), h(1), ... by iterating the formula

  h(n+1) = f(h(n)) + p (n = 0, 1, ..., max_iteration-1)

where p is the fixed 4-D vector parameter of julia_fractal, and f() is one of the functions sqr, cube, ... specified by the presence of the corresponding keyword. The point h(0) that begins the sequence is considered inside the julia_fractal object if none of the vectors in the sequence escapes a hypersphere of radius 4 about the origin before the iteration number reaches the max_iteration value. As you increase the max_iteration, some points escape that did not previously escape, making the julia_fractal. Depending on the JULIA_PARAMETER, the julia_fractal object is not necessarily connected; it may be scattered fractal "dust". Using a low max_iteration can fuse together the dust to make a solid object. A high max_iteration is more accurate but slows rendering. Even though it is not accurate, the solid shapes you get with a low_maximum iteration value can be quite interesting.

Since the mathematical object described by this algorithm is four-dimensional, and POV-Ray renders three dimensional objects, there must be a way to reduce the number of dimensions of the object from four dimensions to three. This is accomplished by intersecting the 4-D fractal with a 3-D "plane" defined by the slice filed and then projecting the intersection to 3-D space. The slice plane is the 3-D space that is perpendicular to NORMAL4D and is DISTANCE units from the origin. Zero length NORMAL4D vectors, or a NORMAL4D vector with a zero fourth component are illegal.

You can get a good feel for the four dimensional nature of a julia_fractal by using POV-Ray's animation feature to vary slice's DISTANCE parameter. You can make the julia_fractal appear from nothing, grow, then shrink to nothing as DISTANCE changes, much as the cross section of a 3-D object changes as it passes through a plane.

The precision parameter is a tolerance used in the determination of whether points are inside or outside the fractal object. Larger values give more accurate results but slower rendering. Use as low a value as you can without visibly degrading the fractal object's appearance.

The presence of the keywords quaternion or hypercomplex determine which 4-D algebra is used to calculate the fractal. Both are 4-D generalizations of the complex numbers but neither satisfies all the field properties (all the properties of real and complex numbers that many of us slept through in high school.) Quaternions have non-commutative multiplication, and hypercomplex numbers can fail to have a multiplicative inverse for some non-zero elements. (It has been proved that you cannot successfully generalize complex numbers to four dimensions with all the field properties intact, so something has to break.) Both of these algebras were discovered in the 19th century. Of the two, the quaternions are much better known, but one can argue that hypercomplex numbers are more useful for our purposes, since complex valued functions such as sin, cos, etc. can be generalized to work for hypercomplex numbers in a uniform way.

For the mathematically curious, the algebraic properties of these two algebras can be derived from the multiplication properties of the unit basis vectors 1 = <1,0,0,0>, i=<0,1,0,0>, j=<0,0,1,0>, and k=<0,0,0,1>. In both algebras 1x = x1 = x for any x (1 is the multiplicative identity). The basis vectors 1 and i behave exactly like the familiar complex numbers 1 and i in both algebras.

Quaternion basis vector multiplication rules:

  ij = k;            jk  = i;   ki = j
  ji = -k;           kj  = -i;  ik = -j
  ii = jj = kk = -1; ijk = -1;

Hypercomplex basis vector multiplication rules:

  ij = k;            jk = -i;   ki = -j
  ji = k;            kj = -i;   ik = -j
  ii = jj = kk = -1; ijk = 1;

A distance estimation calculation is used with the quaternion calculations to speed them up. The proof that this distance estimation formula works does not generalize from two to four dimensions, but the formula seems to work well anyway, the absence of proof notwithstanding!

The presence of one of the function keywords sqr, cube, etc. determine which function is used for f(h) in the iteration formula h(n+1) = f(h(n)) + p. Most of the function keywords work only if the hypercomplex keyword is present; only sqr and cube work with quaternions. The functions are all familiar complex functions generalized to four dimensions.

  Function Keyword    Maps 4-D value h to:
================================================
  sqr                 h*h
  cube                h*h*h
  exp                 e raised to the power h
  reciprocal          1/h
  sin                 sine of h
  asin                arcsine of h
  sinh                hyperbolic sine of h
  asinh               inverse hyperbolic sine of h
  cos                 cosine of h
  acos                arccosine of h 
  cosh                hyperbolic cos of h
  acosh               inverse hyperbolic cosine of h
  tan                 tangent of h
  atan                arctangent of h
  tanh                hyperbolic tangent of h
  atanh               inverse hyperbolic tangent of h
  log                 natural logarithm of h
  pwr(x,y)            h raised to the complex power x+iy        

The first renderings of julia fractals using quaternions were done by Alan Norton and later by John Hart in the '80's. This new POV-Ray implementation follows Fractint in pushing beyond what is known in the literature by using hypercomplex numbers and by generalizing the iterating formula to use a variety of transcendental functions instead of just the classic Mandelbrot "z^2 + c" formula. With an extra two dimensions and eighteen functions to work with, intrepid explorers should be able to locate some new fractal beasties in hyperspace, so have at it!


Section 3.5.1.7
Lathe


A lathe.

The lathe is an object generated from rotating a two-dimensional curve about an axis. This curve is defined by a set of points which are connected by linear, quadratic or cubic spline curves. The syntax is:

lathe { [ linear_spline | quadratic_spline | cubic_spline ] NUMBER_OF_POINTS, <POINT_1>, <POINT_2>, ..., <POINT_n> }

The parameter NUMBER_OF_POINTS determines how many two-dimensional points are forming the curve. These points are connected by linear, quadratic or cubic splines as specified by an optional keyword (the default is linear_spline). Since the curve is not automatically closed, i.e. the first and last points are not automatically connected, you'll have to do this by your own if you want a closed curve. The curve thus defined is rotated about the y-axis to form the lathe object which is centered at the origin.

The following examples creates a simple lathe object that looks like a "thick" cylinder, i.e. a cylinder with a thick wall:

lathe { linear_spline 5, <2, 0>, <3, 0>, <3, 5>, <2, 5>, <2, 0> pigment {Red} }

The cylinder has an inner radius of 2 and an outer radius of 3, giving a wall width of 1. It's height is 5 and it's located at the origin pointing up, i.e. the rotation axis is the y-axis. Note that the first and last point are equal to get a closed curve.

The splines that are used by the lathe and prism objects are a little bit difficult to understand. The basic concept of splines is to draw a curve through a given set of points in a determined way. The linear spline is the simplest spline because it's nothing more than connecting consecutive points with a line. This means that the curve that is drawn between two points only depends on those two points. No additional information is taken into account. Quadratic and cubic splines are different in that they do not only take other points into account when connecting two points but they also look smoother and - in the case of the cubic spline - produce smoother transitions at each point.

Quadratic splines are made of quadratic curves. Each of them connects two consecutive points. Since those two points (call them second and third point) aren't enough to describe a quadratic curve the predecessor of the third point is taken into account when the curve is drawn. Mathematically the relationship (their location on the 2-D plane) between the third and fourth point determines the slope of the curve at the third point. The slope of the curve at the second point is out of control. Thus quadratic splines look much "smoother" than linear splines but the transitions at each point are generally not smooth because the slopes on "both sides" of the point are different.

Cubic splines overcome the transition problem of quadratic splines because they also take the first point into account when drawing the curve between the second and third point. The slope at the second point is under control now and allows a smooth transition at each point. Thus cubic splines produce the most flexible and smooth curves.

You should note that the number of spline segments, i.e. curves between two points, depends on the spline type used. For linear splines you get n-1 segments connecting the points P[i], i=1...n. A quadratic spline gives you n-2 segments because the last point is only used for determining the slope as explained above (thus you'll need at least three points to define a quadratic spline). The same holds for cubic splines where you get n-3 segments with the first and last point used only for slope calculations (thus needing at least four points).

If you want to get a closed quadratic and cubic spline with smooth transitions at the end points you have to make sure that in the cubic case P[n-1] = P[2] (to get a closed curve), P[n] = P[3] and P[n-2] = P[1] (to smooth the transition). In the quadratic case P[n-1] = P[1] (to close the curve) and P[n] = P[2].

Lathe objects respond to automatic bounding and can be translated, rotated and scaled.


Section 3.5.1.8
Prism


A prism.

The prism is an object generated from sweeping a two-dimensional, closed curve along an axis. This curve is defined by a set of points which are connected by linear, quadratic or cubic splines. The syntax is:

prism { [ linear_sweep | conic_sweep ] [ linear_spline | quadratic_spline | cubic_spline ] HEIGHT1, HEIGHT2, NUMBER_OF_POINTS, <POINT_1>, <POINT_2>, ..., <POINT_n> [ open ] [ sturm ] }

The parameter NUMBER_OF_POINTS determines how many two-dimensional points are forming the curve. These points, which are given in the x-z-plane, are connected by linear, quadratic or cubic splines as specified by an optional keyword (the default is linear spline) to get a closed curve. It is swept along the y-axis from HEIGHT1 to HEIGHT2 to form the prism object. By default linear sweeping is used to create the prism, i.e. the prism's walls are perpendicular to the x-z-plane (the size of the curve doesn't change during the sweep). You can also use conic sweeping that leads to a prism with "cone-like" walls by scaling the curve down during the sweep.

Like cylinders the prism is normally closed. You can remove the caps on the prism by using the "open" keyword. If you do so you shouldn't use it with CSG because the results may get wrong.

The following example creates a simple prism object that looks like a piece of cake:

prism { linear_sweep linear_spline 0, 1, 3, <-1, 0>, <1, 0>, <0, 5> pigment {Red} }

For an explanation of the spline concept read the description of the lathe object.

Prism objects respond to automatic bounding and can be translated, rotated and scaled.


Section 3.5.1.9
Sphere


A sphere.

The syntax of the sphere object is:

sphere { <CENTER>, RADIUS }

Where <CENTER> is a vector specifying the x, y, z coordinates of the center of the sphere and RADIUS is a float value specifying the radius. Spheres may be scaled unevenly giving an ellipsoid shape.

Because spheres are highly optimized they make good bounding shapes. Because they are finite they respond to automatic bounding. As with all shapes, they can be translated, rotated and scaled.


Section 3.5.1.10
Superquadric Ellipsoid


A superquadric ellipsoid.

The superquadric ellipsoid is an extension of the quadric ellipsoid. It can be used to create boxes and cylinders with round edges and other interesting shapes. Mathematically it is given by the equation:

f(x, y, z) = (|x|^(2/e) + |y|^(2/e)) ^ (e/n) + |z|^(2/n) - 1 = 0

The values of e and n, called the east-west and north-south exponent, determine the shape of the superquadric ellipsoid. Both have to be greater than zero. The sphere is e.g. given by e = 1 and n = 1.

The syntax of the superquadric ellipsoid is:

superellipsoid { <e, n> }

The object is located at the origin and can be translated, rotated and scaled just like any other object. Since it is finite it responds to automatic bounding.

Two useful objects are the rounded box and the rounded cylinder. These are declared in the following way.

#declare Rounded_Box = superellipsoid { <r, r> } #declare Rounded_Cylinder = superellipsoid { <1, r> }

The roundedness r determines the roundedness of the edges and has to be greater than zero and smaller than one. The smaller you choose the values of r the smaller and sharper the edges will get.

Very small values of e and n might cause problems with the root solver.


Section 3.5.1.11
Surface of Revolution


A surface of revolution.

The surface of revolution (SOR) object is generated by rotating a line about an axis. This line is essentially a function describing the dependence of the radius from the position on the rotation axis.

The syntax of the SOR object is:

sor { NUMBER_OF_POINTS, <POINT1>, <POINT2>, ..., <POINTn> [ open ] }

The points <POINT1> through <POINTn> are two dimensional vectors consisting of the radius and the corresponding position on the rotation axis. These points are smoothly connected and rotated about the y-axis to form the SOR object. The first and last points are only used to determine the slopes of the function at the start and end point. The function used for the SOR object is similar to the splines used for the lathe object. The difference is that the SOR object is less flexible because it underlies the restrictions of any mathematical function, i.e. to any given point y on the rotation axis corresponds at most one radius. You can't rotate closed curves with the SOR object.

The optional keyword "open" allows you to remove the caps on the SOR object. If you do this you shouldn't use it with CSG anymore because the results may get wrong.

The SOR object is useful for creating bottles, vases, and things like that. A simple vase could look like this:

#declare Vase = sor { 7, <0.000000, 0.000000> <0.118143, 0.000000> <0.620253, 0.540084> <0.210970, 0.827004> <0.194093, 0.962025> <0.286920, 1.000000> <0.468354, 1.033755> open }

One might ask why there is any need for a SOR object if there is already a lathe object which is much more flexible. The reason is quite simple. The intersection test with a SOR object includes to solve a cubic polynomial while the test with a lathe object means to solve a 6th order polynomial (you need a cubic spline for the same "smoothness"). Since most SOR and lathe objects will have several segments this will make a great difference in speed. The roots of the 3rd order polynomial will also be more accurate and easier to find.

Surface of revolution objects respond to automatic bounding and can be translated, rotated and scaled.


Next Section
Table Of Contents